package com.hch.netty;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * 原生nio底层实现 服务器端
 */
public class NIOServer {
    private static int port = 9000;

    public static void main(String[] args) throws IOException {
        // 底层: 在linux上面开启socket服务，启动一个线程,绑定ip地址和端口号
        ServerSocketChannel ssc = ServerSocketChannel.open();
        // 设置TCP协议连接 三次握手非阻塞模式
        ssc.configureBlocking(false);
        ssc.socket().bind(new InetSocketAddress(port));
        // 底层： 通过open()方法找到Selector 开启epoll，为当前socket服务创建epoll服务，epoll_create
        Selector selector = Selector.open();
        // 注册到selector，等待连接
        /**  SelectionKey.OP_ACCEPT
         *   SelectionKey.OP_ACCEPT —— 接收连接就绪事件，表示服务器监听到了客户连接
         *   SelectionKey.OP_CONNECT —— 连接就绪事件，表示客户与服务器的连接已经建立就绪
         *   SelectionKey.OP_READ —— 读就绪事件，表示通道中已经有了可读的数据，可以执行读操作
         *   SelectionKey.OP_WRITE —— 写就绪事件，表示已经可以向通道写数据了（通道目前可以用于写操作）
         */
        ssc.register(selector, SelectionKey.OP_ACCEPT);
        while (true) {
            /**
             * 轮询事件监听 阻塞的方法
             */
            int select = selector.select();
            // tcp 数据
            Iterator<SelectionKey> it = selector.selectedKeys().iterator();
            while (it.hasNext()) {
                SelectionKey key = it.next();
                //删除本次已处理的key，防止下次select重复处理
                it.remove();
                handle(key);
            }
        }
    }

    private static void handle(SelectionKey key) throws IOException {
        if (key.isAcceptable()) {
            System.out.println("表示：现在有客户端与我建立三次握手;");
            ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
            SocketChannel sc = ssc.accept();
            // 数据读取通道设置非阻塞的模式
            sc.configureBlocking(false);
            sc.register(key.selector(), SelectionKey.OP_READ);
        } else if (key.isReadable()) {
            System.out.println("表示：客户端发送数据给服务器端；");
            SocketChannel sc = (SocketChannel) key.channel();
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            int len = sc.read(buffer);
            if (len != -1) {
                System.out.println(Thread.currentThread().getName() + "读取到客户端发送的数据：" + new String(buffer.array(), 0, len));
            }
            ByteBuffer bufferToWrite = ByteBuffer.wrap("6666".getBytes());
            sc.write(bufferToWrite);
        }
    }

}